#pragma once

#include "VertexFactory.h"

#include "Shader.h"

namespace RenderSystem
{
	class SubMeshInstance;
	class LocalVertexFactoryShaderParameters : public VertexFactoryShaderParameters
	{
	public:
		/**
		* Bind shader constants by name
		* @param	ParameterMap - mapping of named shader constants to indices
		*/
		virtual void Bind(const ShaderParameterMap& rParameterMap);

		/**
		* Set any shader data specific to this vertex factory
		*/
		virtual void Set(Shader* pVertexShader, const VertexFactory* pVertexFactory) const;
		virtual void SetMesh(Shader* pVertexShader, const SubMeshInstance& rSubMeshInstance) const;

	protected:

		ShaderParameter				m_LocalToWorldParameter;
		ShaderParameter				m_LocalToWorldRotDeterminantFlipParameter;
		ShaderParameter				m_WorldToLocalParameter;
	};

	/**
	* A vertex factory which simply transforms explicit vertex attributes from local to world space.
	*/
	class LocalVertexFactory : public VertexFactory
	{
		DECLARE_VERTEX_FACTORY_TYPE(LocalVertexFactory);
	public:

		struct DataType : public VertexFactory::DataType
		{
			/** The stream to read the vertex position from. */
			VertexStreamComponent objPositionComponent;

			/** The streams to read the tangent basis from. */
			VertexStreamComponent objTangentBasisComponents[2];

			/** The streams to read the texture coordinates from. */
			std::vector<VertexStreamComponent> objTextureCoordinates;

			/** The stream to read the shadow map texture coordinates from. */
			VertexStreamComponent objShadowMapCoordinateComponent;

			/** The stream to read the vertex color from. */
			VertexStreamComponent objColorComponent;
		};

		/**
		* An implementation of the interface used by TSynchronizedResource to update the resource with new data from the game thread.
		*/
		void SetData(const DataType& InData)
		{
			Data = InData;
			UpdateRHI();
		}

		/**
		* Copy the data from another vertex factory
		* @param Other - factory to copy from
		*/
		void Copy(const LocalVertexFactory& Other);

		/**
		* Vertex factory interface for creating a corresponding decal vertex factory
		* Copies the data from this existing vertex factory.
		*
		* @return new allocated decal vertex factory
		*/
		virtual class FDecalVertexFactoryBase* CreateDecalVertexFactory() const;

		// FRenderResource interface.
		virtual void InitRHI();

	protected:
		DataType Data;
	};


	/**
	* Vertex factory for all shadow volumes.
	*/
	class LocalShadowVertexFactory : public VertexFactory
	{
		DECLARE_VERTEX_FACTORY_TYPE(LocalShadowVertexFactory);
	public:

		struct DataType
		{
			// Constructor.
			DataType(): BaseExtrusion(0.0f)	{}

			/** The stream to read the vertex position from. */
			VertexStreamComponent	PositionComponent;

			/**
			* The stream to read the extrusion flag from
			* (greater than 0.5f means the vertex should be extruded).
			*/
			VertexStreamComponent	ExtrusionComponent;

			/** A small distance to extrude front-facing vertices. */
			FLOAT BaseExtrusion;
		};

		/**
		* An implementation of the interface used by TSynchronizedResource to update
		* the resource with new data from the game thread.
		*/
		void SetData(const DataType& InData)
		{
			Data = InData;
			UpdateRHI();
		}

		/** Returns the small distance to extrude front-facing vertices. */
		FLOAT GetBaseExtrusion() const
		{
			return Data.BaseExtrusion;
		}

		// FRenderResource interface.
		virtual void InitRHI()
		{
			VertexDeclarationElementList Elements;
			Elements.AddItem(AccessStreamComponent(Data.PositionComponent,VEU_Position));
			Elements.AddItem(AccessStreamComponent(Data.ExtrusionComponent,VEU_TextureCoordinate,0));
			InitDeclaration(Elements,FVertexFactory::DataType());
		}

	private:
		DataType	m_rData;
	};



}